#!/usr/bin/python2.7
#
# Copyright 2012 Twist Inc.
#
#
import datetime
import time
import unittest

from collections import deque

from google.appengine.ext import ndb

from apiclient.errors import HttpError
from log2bq import gsbucketname, CleanUpOldRuns, Log2BqHandler, LogsRun, VersionId
from tests.utils import TestCase



class FakeStorageClient(object):
    def __init__(self):
        self.requests = []
        self.responses = deque()

    def request(self, uri, method='GET'):
        self.requests.append({'uri': uri, 'method': method})
        if self.responses:
            return self.responses.popleft()
        return {'status': '204'}, 'boring content'

    def add_response(self, resp, content):
        self.responses.append((resp, content))


class TestCleanUpOldRuns(CleanUpOldRuns):
    def __init__(self):
        super(CleanUpOldRuns, self).__init__()
        self.storage_http = FakeStorageClient()
        self.bigquery_exceptions = deque()
        self.gs_prefix_len = len('/gs/%s/' % gsbucketname)

    def delete_bigquery_table(self, table):
        if self.bigquery_exceptions:
            raise self.bigquery_exception.popleft()


class Log2BqTest(TestCase):
    def setUp(self):
        super(Log2BqTest, self).setUp()
        self.old_runs = TestCleanUpOldRuns()

    def create_logs_run(self, days_ago=0):
        old_run = LogsRun.new_instance(time.time(), time.time())
        old_run.files = ['/gs/%s/%s-unique-file-1' % (gsbucketname, days_ago),
                         '/gs/%s/%s-5678' % (gsbucketname, days_ago)]
        old_run.table = 'bqtable-%s' % days_ago
        old_run.put()
        old_run.create_gmt = datetime.datetime.now() - datetime.timedelta(days=days_ago)
        old_run.put()

    def test_cleanup_logs_only_old_logs(self):
        self.create_logs_run(days_ago=31)
        self.create_logs_run(days_ago=2)
        self.old_runs.run()
        self.assertEqual(2, len(self.old_runs.storage_http.requests))
        self.assertEqual('https://log2bq_logs.storage.googleapis.com/31-unique-file-1',
                         self.old_runs.storage_http.requests[0]['uri'])
        self.assertEqual('DELETE', self.old_runs.storage_http.requests[0]['method'])
        self.assertEqual('https://log2bq_logs.storage.googleapis.com/31-5678',
                         self.old_runs.storage_http.requests[1]['uri'])
        logs_runs = LogsRun.query().fetch(100)
        self.assertEqual(1, len(logs_runs))
        self.assertEqual('bqtable-2', logs_runs[0].table)

    def test_cleanup_logs_bigquery_exceptions(self):
        self.create_logs_run(days_ago=34)
        self.create_logs_run(days_ago=32)
        self.create_logs_run(days_ago=31)
        self.old_runs.bigquery_exceptions.append(HttpError({'status': '404'}, 'foo'))
        self.old_runs.bigquery_exceptions.append(HttpError({'status': '500'}, 'foo'))
        self.old_runs.run()

        logs_runs = LogsRun.query().fetch(100)
        self.assertEqual(1, len(logs_runs))
        self.assertEqual('bqtable-32', logs_runs[0].table)

    def test_cleanup_logs_bigquery_exceptions(self):
        self.create_logs_run(days_ago=34)
        self.old_runs.storage_http.add_response({'status': '500'}, 'content')
        self.old_runs.run()

        self.assertEqual(1, len(self.old_runs.storage_http.requests))

        logs_runs = LogsRun.query().fetch(100)
        self.assertEqual(1, len(logs_runs))
        self.assertEqual('bqtable-34', logs_runs[0].table)


class TestLog2BqHandler(TestCase):
    def test_get_version_ids(self):
        now = datetime.datetime.utcnow()
        self.assertEqual(['beta'], Log2BqHandler.get_version_ids([], now))

        versions = []
        version = VersionId.new_instance(1)
        version.create_gmt = now - datetime.timedelta(days=5)
        version.modification_gmt = now - datetime.timedelta(days=2)
        versions.append(version)

        version = VersionId.new_instance(2)
        version.create_gmt = now - datetime.timedelta(days=7)
        version.modification_gmt = now - datetime.timedelta(days=7)
        versions.append(version)

        version = VersionId.new_instance(3)
        version.create_gmt = now - datetime.timedelta(days=1)
        version.modification_gmt = now - datetime.timedelta(days=1)
        versions.append(version)

        self.assertEqual([3, 1, 'beta'], Log2BqHandler.get_version_ids(versions, now))
        self.assertEqual([3, 1, 2, 'beta'],
                         Log2BqHandler.get_version_ids(versions, now - datetime.timedelta(days=8)))

    def test_pipeline(self):
        now = time.time()
        old_run = LogsRun.new_instance(now, now + 600)
        old_run.files = ['/gs/twist_logs/file']
        old_run.table = 'bqtable'
        old_run.put()

        handler = Log2BqHandler()
        with self.assertRaises(AssertionError):
            handler.pipeline()

        old_run.key.delete()
        pipeline = handler.pipeline()
        self.assertAlmostEqual(pipeline.args[0], now - 24*60*60, delta=10)
        self.assertAlmostEqual(pipeline.args[1], now - 60, delta=10)
